package reflect;

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @description: 动态代理
 * @author: apple
 * @date:  2021/12/30 11:47 下午
 * @version 1.0
 **/
public class ProxyTest {

    @Test
    public void test1() {

        // 该类集成自Proxy，实现Human接口
        final Human human = (Human) ProxyFactory.getProxyInstance(new SuperMan());
    }
}


interface Human {

    String xinyang();

    void eat(String food);
}

/*
被代理类
 */
class SuperMan implements Human {
    @Override
    public String xinyang() {
        return "维护世界和平";
    }

    @Override
    public void eat(String food) {
        System.out.println("超人正在吃：" + food);
    }
}

/*
问题1：如何根据被代理类动态创建代理类
问题2：通过代理类调用方法，怎么同时调用被代理类的同名方法
 */
class ProxyFactory {


    // 获取一个被代理类对象
    public static Object getProxyInstance(Object obj) { // obj被代理类对象

        // 动态创建一个代理类对象

        MyInvocationHandler callBack = new MyInvocationHandler(obj);

        final Object o = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), callBack);
        Class source =  o.getClass();

        System.out.println(o + "->" + source);
        System.out.println(source.getName());
        System.out.println(source.getSuperclass());
        System.out.println(source.getInterfaces()[0]);
        return o;
    }
}

// 动态代理类会调用这个类的invoke方法（回调工具）
class MyInvocationHandler implements InvocationHandler {

    Object obj;

    public MyInvocationHandler(Object obj) {
        this.obj = obj;
    }

    // 代理类调用方法时，会调用这个，参数1代表被代理类对象，参数2代表被代理类的对象要执行的方法，方法的参数
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 被代理类对象调用此方法
        return method.invoke(obj,args);
    }
}